package ga.individuals;

import ga.GARun;

public class Individual implements Comparable<Individual> {
	private Double individualValue;
	private Double fitnessValue;
	
	/*
	 * Transforma una array de bytes en un double
	 */
	public static Double toDoubleValue (byte[] doubleBytes) {
		long l = 0L;
		for(int i =0; i < 4; i++){      
		   l <<= 8;  
		   l ^= (long)doubleBytes[i] & 0xFF;      
		}
		return Double.longBitsToDouble(l);
	}
	
	/*
	 * Devuelve el array de bytes correspondiente al double reicibido
	 */
	public static byte[] toByteArray (Double doubleValue) {
		long l = Double.doubleToRawLongBits(doubleValue);
		byte[] b = new byte[4];  
		for(int i= 0; i < 4; i++){  
			b[3 - i] = (byte)(l >>> (i * 8));  
		}
		return b;
	}
	
	public Individual(Double individualValue) {
		this.individualValue = individualValue;
		if (this.individualValue.isNaN() || this.individualValue.isInfinite()) {
			this.fitnessValue = 0.0001;
		} else {
			if (GARun.fitnessMethod.trim().toUpperCase().equals("MAXIMIZE")) {
				this.fitnessValue = Fitness.maximize(this);
			} else {
				this.fitnessValue = Fitness.minimize(this);
			}
		}
	}

	public Double getIndividualValue() {
		return individualValue;
	}

	public void setIndividualValue(Double individualValue) {
		this.individualValue = individualValue;
	}

	public Double getFitnessValue() {
		return fitnessValue;
	}

	public void setFitnessValue(Double fitnessValue) {
		this.fitnessValue = fitnessValue;
	}
	
//	public void adjustIndividual () {
//		if (this.individualValue.isNaN() || this.individualValue.isInfinite()) {
//			this.individualValue = 0.0;
//		}
//		Integer valueForAdjusting = (GARun.maxIndividualValue - GARun.minIndividualValue);
//		if (this.individualValue * valueForAdjusting > 0) {
//			valueForAdjusting *= -1;
//		}
//		while (this.individualValue < GARun.minIndividualValue || this.individualValue > GARun.maxIndividualValue) {
//			this.individualValue += valueForAdjusting;
//		}
//		this.fitnessValue = Fitness.maximize(this);
//	}
	
	public void adjustIndividual () {
		if (this.individualValue.isNaN() || this.individualValue.isInfinite()) {
			this.fitnessValue = 0.0001;
		} else {
			this.individualValue = Math.signum(this.individualValue) * (Math.abs(this.individualValue) % GARun.maxIndividualValue);
			if (GARun.fitnessMethod.trim().toUpperCase().equals("MAXIMIZE")) {
				this.fitnessValue = Fitness.maximize(this);
			} else {
				this.fitnessValue = Fitness.minimize(this);
			}
		}
	}

	@Override
	public int compareTo(Individual otherIndividual) {
		if (this.fitnessValue - otherIndividual.fitnessValue < 0) {
			return -1;
		} else if (this.fitnessValue == otherIndividual.fitnessValue) {
			return 0;
		}
		return 1;
	}

	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result
				+ ((fitnessValue == null) ? 0 : fitnessValue.hashCode());
		result = prime * result
				+ ((individualValue == null) ? 0 : individualValue.hashCode());
		return result;
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		Individual other = (Individual) obj;
		if (fitnessValue == null) {
			if (other.fitnessValue != null)
				return false;
		} else if (!fitnessValue.equals(other.fitnessValue))
			return false;
		if (individualValue == null) {
			if (other.individualValue != null)
				return false;
		} else if (!individualValue.equals(other.individualValue))
			return false;
		return true;
	}

	public boolean isSimilar(Individual individual) {
		return Math.abs(this.getIndividualValue() - individual.getIndividualValue()) <= 0.000001;
	}
	
	@Override
	public String toString() {
		return "Individual [individualValue=" + individualValue
				+ ", fitnessValue=" + fitnessValue + "]";
	}

}
